/*
 *  FSDefineButton.h
 *  Transform SWF
 * 
 * Copyright (c) 2001-2004 Flagstone Software Ltd.. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 *  * Neither the name of Flagstone Software Ltd. nor the names of its contributors 
 *    may be used to endorse or promote products derived from this software 
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __FSDefineButton_h__
#define __FSDefineButton_h__

#include "FSDefineObject.h"

#include "FSVector.h"
#include "FSButton.h"
#include "FSActionObject.h"

#ifdef WIN32
#ifdef _WINDLL
DLL_TEMPLATE template class DLL_DECL transform::FSVector<transform::FSButton>;
DLL_TEMPLATE template class DLL_DECL transform::FSVector<transform::FSActionObject*>;
#endif // _WINDLL
#endif // WIN32

namespace transform
{
/**
 * %FSDefineButton defines the appearance of a button and the actions performed when the 
 * button is clicked.
 * 
<table class="datasheet">

<tr><th align="left" colspan="2">Attributes</th></tr>

<tr>
<td><a name="FSAction_0">type</a></td>
<td>Identifies the action when it is encoded. Read-only.</td>
</tr>
<tr>
<td><a name="FSDefineButton_1">identifier</a></td>
<td>An unique identifier for this object, in the range 1..65535.</td>
</tr>

<tr>
<td><a name="FSDefineButton_2">buttonRecords</a></td>
<td>an array of FSButton objects that define the appearance of the button in each of its states. The array must contain at least one FSButton object.</td>
</tr>

<tr>
<td><a name="FSDefineButton_3">actions</a></td>
<td>an array of action objects that are executed when the button is clicked.</td>
</tr>

<tr><td><a name="FSDefineButton_4">encodedActions</a></td>
<td>An array of bytes containing encoded actions can also be set. The encoded actions are typically generated by the parser in the Translate framework. The actions array and encodedActions cannot both be valid at the same time. Accessor methods used to set either of the attributes will set the other to null.</td>
</tr>

</table>

<p>A FSDefineButton object must contain at least one FSButton object. If more than one button record is defined for a given button state then each shape will be displayed by the button. The order in which the shapes are displayed is determined by the layer assigned to each FSButton object.</P>

<h1 class="datasheet">Examples</h1>

<p>1. Define a simple button that highlights itself when the mouse is move over it. No actions are performed when the button is clicked.</p>

<pre>
FSDefineShape* normal = new FSDefineShape(movie.newIdentifier(), bounds, lineStyles, fillStyles, shape);
FSDefineShape* highlight = new FSDefineShape(movie.newIdentifier(), bounds, lineStyles, fillStyles, highlightShape);

FSVector&lt;FSButton&gt; records;
FSVector&lt;FSActionObject*&gt; actions;

records.push_back(FSButton(FSButton::Up, normal-&gt;getIdentifier(), 1));
records.push_back(FSButton(FSButton::Over, highlight-&gt;getIdentifier(), 2));

FSDefineButton* button = new FSDefineButton(movie.newIdentifier(), records, actions);
</pre>


<p>2. Define a "complex" button that highlights itself when the mouse is move over it and actions are executed when the button is clicked.</p>

<pre>
FSDefineShape* upShape = new FSDefineShape(movie.newIdentifier(), bounds, lineStyles, fillStyles, shape1);
FSDefineShape* overShape = new FSDefineShape(movie.newIdentifier(), bounds, lineStyles, fillStyles, shape2);
FSDefineShape* downShape = new FSDefineShape(movie.newIdentifier(), bounds, lineStyles, fillStyles, shape3);

FSVector&lt;FSButton&gt; records;

records.push_back(FSButton(FSButton::Up, upShape-&gt;getIdentifier(), 1));
records.push_back(FSButton(FSButton::Over, overShape-&gt;getIdentifier(), 2));
records.push_back(FSButton(FSButton::Down, downShape-&gt;getIdentifier(), 3));

FSVector&lt;FSActionObject*&lt; actions;

actions.push_back(action);
actions.push_back(action);
actions.push_back(action);

FSDefineButton* button = new FSDefineButton(movie.newIdentifier(), records, actions);
</pre>


<p>3. If more than one button record is defined for a state then the layer number defines the order the shapes are displayed. This allows buttons to be "reused" with only the label on the button being changed.</p>

<pre>
FSDefineShape* upShape = new FSDefineShape(movie.newIdentifier(), bounds, lineStyles, fillStyles, shape1);
FSDefineShape* overShape = new FSDefineShape(movie.newIdentifier(), bounds, lineStyles, fillStyles, shape2);
FSDefineShape* downShape = new FSDefineShape(movie.newIdentifier(), bounds, lineStyles, fillStyles, shape3);

// The label shape contains the "text" for the button.

FSDefineShape* label = new FSDefineShape(movie.newIdentifier(), bounds, lineStyles, fillStyles, shape4);

FSVector&lt;FSButton&gt; records;

// Note that the label defined for all of the button's states. This ensures the 
// label is visible at all times when the mouse is moved over the button.

records.push_back(FSButton(FSButton::Up, upShape-&gt;getIdentifier(), 1));
records.push_back(FSButton(FSButton::Up, label-&gt;getIdentifier(), 2));
records.push_back(FSButton(FSButton::Over, overShape-&gt;getIdentifier(), 3));
records.push_back(FSButton(FSButton::Over, label-&gt;getIdentifier(), 4));
records.push_back(FSButton(FSButton::Down, downShape-&gt;getIdentifier(), 5));
records.push_back(FSButton(FSButton::Down, label-&gt;getIdentifier(), 6));

FSVector<FSActionObject*> actions;

actions.push_back(action);
actions.push_back(action);
actions.push_back(action);

FSDefineButton* button = new FSDefineButton(movie.newIdentifier(), records, actions);
</pre>


<h1 class="datasheet">History</h1>

<p>The FSDefineButton class represents the DefineButton structure from the Macromedia Flash (SWF) File Format Specification. It was introduced in Flash 1.</p>

 */
    class DLL_DECL FSDefineButton : public FSDefineObject
    {
public:
        FSDefineButton(FSInputStream* aStream);

        /**  Constructs an FSDefineButton object with the identifier, button records and actions.

            @param anIdentifier a unique identifier for this button.
            @param buttonRecordArray an array of FSButton objects.
            @param actionArray and array of action objects.
        */
        FSDefineButton(int anIdentifier, FSVector<FSButton> buttonRecordArray, FSVector<FSActionObject*> actionArray) : FSDefineObject(DefineButton, anIdentifier), buttonRecords(buttonRecordArray), actions(actionArray) {}

        FSDefineButton(const FSDefineButton& rhs);

        ~FSDefineButton();

        FSDefineButton& operator= (const FSDefineButton& rhs);

        FSDefineButton* clone() const { return new FSDefineButton(*this); }

        const char* className() const;

        /** Adds a button record object to the array of button records.

            @param aButtonRecord a button record.
            */
        void add(FSButton& aButtonRecord) { buttonRecords.push_back(aButtonRecord); }

        /** Adds all the button records in an array to the buttonRecords.

            @param anArray an array of button record objects.
            */
        void add(const FSVector<FSButton>& anArray);

        /** Adds an action to the array of actions.

            @param anAction an action.
            */
        void add(FSActionObject* anAction) { actions.push_back(anAction); }

        /** Adds all the actions in an array to the array of actions.

            @param anArray an array of pointers to action objects.
            */
        void add(const FSVector<FSActionObject*>& anArray);

        /** Gets the array of button records defined for this button.

            @return the array of FSButton objects defined for this button.
            */
        FSVector<FSButton>& getButtonRecords() { return buttonRecords; }

        /** Gets the array of actions that will be executed when the button is clicked an released.

            @return the array of action objects defined for this button.
            */
        FSVector<FSActionObject*>& getActions() { return actions; }

        /** Sets the array of button records defined for this button.

            @param anArray an array of FSButton objects.
            */
        void setButtonRecords(const FSVector<FSButton>& anArray) { buttonRecords = anArray; }

        /** Sets the array of actions that will be executed when the button is clicked an released.

            @param anArray an array of action objects.
            */
        void setActions(const FSVector<FSActionObject*>& anArray);
    
        int lengthInStream(FSOutputStream* aStream);
        void encodeToStream(FSOutputStream* aStream);
        void decodeFromStream(FSInputStream* aStream);

private:
        FSVector<FSButton> buttonRecords;
        FSVector<FSActionObject*> actions;
    };
}    

#endif
